package event

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/unitedrhino/protocol-wumei/service/pwumeisvr/internal/svc"
	"gitee.com/unitedrhino/share/utils"
	"gitee.com/unitedrhino/things/share/devices"
	"gitee.com/unitedrhino/things/share/domain/deviceMsg"
	"gitee.com/unitedrhino/things/share/domain/deviceMsg/msgOta"
	"gitee.com/unitedrhino/things/share/domain/deviceMsg/msgThing"
	"gitee.com/unitedrhino/things/share/domain/schema"
	"github.com/spf13/cast"
	"github.com/zeromicro/go-zero/core/logx"
	"time"
)

type DeviceDown struct {
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDeviceDown(ctx context.Context, svcCtx *svc.ServiceContext) *DeviceDown {
	return &DeviceDown{
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

type Body struct {
	Id    string `json:"id"`
	Value any    `json:"value"`
}

var (
	ControlSucc = `
{
  "method":"controlReply",
  "msgToken":"%s",
  "code":200,
  "msg":"ok"
}
 
`
)

func (d *DeviceDown) Handle(ctx context.Context, info *devices.InnerPublish) error {
	d.Info(info)
	switch info.Handle {
	case devices.Thing:
		switch info.Type {
		case msgThing.TypeProperty:
			var resp msgThing.Req
			err := json.Unmarshal(info.Payload, &resp)
			if err != nil {
				return err
			}
			switch resp.Method {
			case deviceMsg.Control:
				var bodies []Body
				for k, v := range resp.Params {
					id, num, ok := schema.GetArray(k)
					if ok { //数组类型
						bodies = append(bodies, Body{Id: fmt.Sprintf("array_%02d_%s", num, id), Value: utils.Fmt(v)})
					} else {
						bodies = append(bodies, Body{Id: k, Value: utils.Fmt(v)})
					}
				}
				payload, err := json.Marshal(bodies)
				if err != nil {
					return err
				}
				err = d.svcCtx.Protocol.PublishToDev(ctx, fmt.Sprintf("/%s/%s/function/get", info.ProductID, info.DeviceName), payload)
				if err != nil {
					return err
				}
				err = d.svcCtx.Protocol.DevPubMsg(ctx, &devices.DevPublish{
					Topic:      "",
					Timestamp:  time.Now().UnixMilli(),
					ProductID:  info.ProductID,
					DeviceName: info.DeviceName,
					Handle:     info.Handle,
					Type:       info.Type,
					Payload:    []byte(fmt.Sprintf(ControlSucc, resp.MsgToken)),
				})
				if err != nil {
					return err
				}
			}
		}
	case devices.Ota:
		switch info.Type {
		case msgOta.TypeUpgrade:
			var req msgOta.Upgrade
			err := json.Unmarshal(info.Payload, &req)
			if err != nil {
				return err
			}
			w := OtaReq{
				Version:     cast.ToFloat64(req.Data.Version),
				DownloadUrl: req.Data.FileUrl,
			}
			payload, err := json.Marshal(w)
			if err != nil {
				return err
			}
			err = d.svcCtx.Protocol.PublishToDev(ctx, fmt.Sprintf("/%s/%s/ota/get", info.ProductID, info.DeviceName), payload)
		}
	}
	return nil
}

type OtaReq struct {
	Version     float64 `json:"version"`
	DownloadUrl string  `json:"downloadUrl"`
}
